#!usr/bin/env python
# -*- coding: utf-8 -*-

#第九章 元编程

#装饰器

import time
import types

from functools import wraps,partial
from inspect import signature

def logAndTime(func):
    @wraps(func) # 主要是保存函数的元信息不会丢失 元信息比如名字、文档字符串、注解和参数签名
    def wrapper(*arg,**kwarg):
        st = time.time()

        print("arg,kwarg",arg,kwarg)
        ret = func(*arg,**kwarg)
        et = time.time()
        print(func.__name__,et-st)
        return ret
    return wrapper

@logAndTime
def cal(n):
    while n>0:
        n-=1
    
# cal.__wrapped__ 只有通过 @wraps(func) 处理过的函数才有该属性 该属性就是函数本身
# signature(cal) 获取函数的参数签名
print(cal(1000000))
    

def add(x:int,y):
    return x+y

sig = signature(add) # 获取函数的签名信息
print(sig,sig.parameters)

# 定义一个类装饰器
class Profile():
    def __init__(self,fn):
        wraps(fn)(self)
        self.callN=0
    def __call__(self,*arg,**kwarg):
        self.callN+=1
        print("call func ",self.__wrapped__.__name__,self.callN,"times")
        return self.__wrapped__(*arg,**kwarg) #其实是一个描述器原理 在自身内部找不到属性 会执行 __get__
        
    # 这个方法的设定不少 否则对类方法添加装饰器的时候就会出问题 
    def __get__(self,instance,cls):# 为了确保绑定方法对象能被正确的创建
        print("__get__ instance,cls",instance,cls)
        if instance is None:
            return self
        else:
            ret = types.MethodType(self,instance)
            print("ret=",ret)
            return ret

@Profile
def add2(x,y):
    return x+y

print(add2(2,3))

class Spam():
    
    @Profile
    def bar(self):
        print("spam bar")

    
s = Spam()

s.bar()

# 通过元类实现单例模式

class Singletion(type):
    def __init__(self,*arg,**kwarg):
        self._inst = None
        super().__init__(*arg,**kwarg)

    def __call__(self,*arg,**kwarg):
        if self._inst is None:
            self._inst = super().__call__(*arg,**kwarg)
            return self._inst
        else:
            return self._inst

class MyInst(metaclass=Singletion): #注册元类
    def __init__(self):       
        print("create MyInst ")


myObj1 = MyInst()
myObj2 = MyInst()

print(myObj1 is myObj2)